1 module hip.ai.steering; 2 version(Test): 3 import hip.math.random; 4 import hip.math.utils; 5 public import hip.math.utils:AxisNavigation; 6 public import hip.math.vector; 7 8 Vector3 seek(Vector3 target, Vector3 position, float speed, float dt) 9 { 10 Vector3 dir = target-position; 11 dir.normalize; 12 return dir*speed*dt; 13 } 14 Vector3 seekAndStop(Vector3 target, Vector3 position, float speed, float dt) 15 { 16 Vector3 dir = target-position; 17 Vector3 velocity = dir; 18 velocity.normalize; 19 velocity*=speed*dt; 20 21 if(velocity.mag > dir.mag) 22 return dir; 23 return velocity; 24 } 25 26 27 Vector3 arrive(Vector3 target, Vector3 position, float slowdownFactor, float speed, float dt) 28 { 29 Vector3 dir = target-position; 30 slowdownFactor = (dir.mag/slowdownFactor); 31 dir.normalize; 32 return dir*(speed*slowdownFactor*dt); 33 } 34 35 36 Vector3 pursuit(Vector3 target, Vector3 targetVelocity, Vector3 position, float speed, float dt, float predictionFactor = 1) 37 { 38 Vector3 dir = (target+(targetVelocity*predictionFactor)) - position; 39 dir.normalize; 40 return dir*(speed*dt); 41 } 42 43 Vector3 flee(Vector3 target, Vector3 position, float speed, float dt) 44 { 45 Vector3 dir = target-position; 46 dir.normalize; 47 return dir*(-speed*dt); 48 } 49 50 Vector3 evade(Vector3 target, Vector3 targetVelocity, Vector3 position, float speed, float dt,float predictionFactor = 1) 51 { 52 Vector3 dir = (target+(targetVelocity*predictionFactor)) - position; 53 dir.normalize; 54 return dir*(-speed*dt); 55 } 56 57 enum WanderAxis 58 { 59 xy, yz, xz, zx, zy, yx 60 } 61 62 Vector3 wander( 63 Vector3 velocity, 64 Vector3 displacement, 65 float circleDistance, 66 float circleRadius, 67 ref float wanderAngle, 68 float angleChangeFactor, 69 float speed, 70 float dt, 71 AxisNavigation axis = AxisNavigation.xy 72 ) 73 { 74 Vector3 circle = velocity; 75 circle.normalize; 76 circle*= circleDistance; 77 displacement.normalize; 78 displacement*= circleRadius; 79 80 wanderAngle+= Random.rangef(0, 2) * angleChangeFactor - angleChangeFactor*0.5f; 81 displacement = toCircleBounds(displacement, wanderAngle, axis); 82 83 Vector3 wanderForce = circle+displacement; 84 85 return wanderForce * (speed*dt); 86 } 87 88 struct PathFollowerStatus 89 { 90 Vector3[] waypoints; 91 uint currentWaypoint; 92 this(Vector3[] waypoints) 93 { 94 this.waypoints = waypoints; 95 currentWaypoint = 0; 96 } 97 98 pragma(inline, true) Vector3 getWaypoint(){return waypoints[currentWaypoint];} 99 pragma(inline, true) bool hasFinished(){return currentWaypoint >= waypoints.length;} 100 pragma(inline, true) void checkAdvance(ref Vector3 pos, float range) 101 { 102 if(!hasFinished && getWaypoint.distance(pos) <= range) 103 { 104 currentWaypoint++; 105 } 106 } 107 } 108 109 Vector3 pathFollow(Vector3 position, ref PathFollowerStatus status, float speed, float dt, float minRange=0) 110 { 111 status.checkAdvance(position, minRange); 112 if(status.hasFinished) 113 return Vector3.zero; 114 return seekAndStop(status.getWaypoint, position, speed, dt); 115 } 116 117 118 //Incomplete 119 void flocking( 120 Vector3 position, float perceptionRadius, 121 ref Vector3 alignment, 122 Vector3[] groupPosition, Vector3[] groupAlignment 123 ) 124 { 125 126 Vector3 alignmentSteering = Vector3.zero; 127 size_t groupSize = 0; 128 for(size_t i = 0; i < groupPosition.length; i++) 129 { 130 if(groupPosition[i] != position && position.distance(groupPosition[i]) <= perceptionRadius) 131 { 132 alignmentSteering = alignmentSteering + groupPosition[i]; 133 groupSize++; 134 } 135 } 136 if(groupSize != 0) 137 { 138 alignmentSteering/= groupSize; 139 alignment = alignment - alignmentSteering; 140 } 141 142 }